/*
  1: 转发给中转  通过TCP
*/

package WsPorxy

import (
	"bytes"
	"crypto/md5"
	"encoding/binary"
	"fmt"
	"net"
	"sync"
	"time"
	"utils"

	"golang.org/x/net/websocket"
)

type WsToTcp struct {
	Conn                *net.TCPConn
	m_cbDataBuffer      [utils.SOCKET_TCP_BUFFER]byte //接受缓冲
	m_NetBuf            *utils.CTCPSocket             //msg 解析
	m_RecvNetBuf        *utils.CTCPSocket             //msg 解析
	m_AssembleBuf       *utils.CTCPSocket
	SysUserLog          *utils.MyLog
	m_ws                *websocket.Conn
	m_Timestamp         uint32
	m_TransType         byte
	m_OnlyMark          string
	m_bvalidationSucces bool
	lock                *sync.Mutex
	m_hc                *WebSocketControl
	maddr               string
	Closechan           chan bool
}

func MakeNewWsToTcp(hc *WebSocketControl) *WsToTcp {
	manager := &WsToTcp{
		Conn:                nil,
		lock:                new(sync.Mutex),
		m_bvalidationSucces: false,
		m_hc:                hc,
		Closechan:           make(chan bool),
	}

	manager.m_NetBuf = utils.MarkNewTCPScoket("ProxySercer To CoreServer:", manager.PrintLog)
	manager.m_RecvNetBuf = utils.MarkNewTCPScoket("CoreServer To ProxySercer:", manager.PrintLog)
	manager.m_AssembleBuf = utils.MarkNewTCPScoket("AssembleBuf:", manager.PrintLog)

	for i := 0; i < utils.SOCKET_TCP_BUFFER; i++ {
		manager.m_cbDataBuffer[i] = 0
	}

	return manager
}

func (this *WsToTcp) ConnentFoxServer(addr string, ws *websocket.Conn) bool {

	if this.Conn == nil {
		this.m_ws = ws
		this.maddr = addr
		netAddr, err := net.ResolveTCPAddr("tcp", addr)
		if err != nil {
			this.PrintLog(this.m_OnlyMark, fmt.Sprintf("ConnentFoxServer ResolveTCPAddr Error: %s, ERROR:%s", addr, err.Error()))
			return false
		}
		this.Conn, err = net.DialTCP("tcp", nil, netAddr)
		if err != nil {
			this.PrintLog(this.m_OnlyMark, fmt.Sprintf("error connect to server@%s ERROR: %s", addr, err.Error()))
			return false
		}

		if err == nil {
			go this.Start()
		}
		this.PrintLog(this.m_OnlyMark, "Create Connect CoreServer Success!")
		return true
	} else {
		fmt.Println(this.m_OnlyMark, "CoreServer Socket Is existed!")
	}

	return true
}

func (this *WsToTcp) ConnectVerifcation() {

	CmdVerifcation := new(utils.TCP_Verifcation)
	CmdVerifcation.TransType = byte(utils.GetRandom(1, 9))
	CmdVerifcation.Timestamp = uint32(time.Now().Unix())

	this.m_TransType = CmdVerifcation.TransType
	this.m_Timestamp = CmdVerifcation.Timestamp

	buf_w := new(bytes.Buffer)
	binary.Write(buf_w, binary.LittleEndian, CmdVerifcation)
	this.m_NetBuf.SendData(utils.MDM_KN_COMMAND, utils.SUB_KN_VALIDATE_SOCKET, buf_w.Bytes(), uint16(binary.Size(CmdVerifcation)), this.m_ws, 0, this.m_OnlyMark)

	this.PrintLog(this.m_OnlyMark, fmt.Sprintf("Create private key: m_TransType:%d  m_Timestamp:%d", this.m_TransType, this.m_Timestamp))
}

//写日志
func (this *WsToTcp) PrintLog(key, log string) {

	if this.SysUserLog != nil {
		this.SysUserLog.PutLineAsLog("[" + key + "]" + ": " + log)
	} else if utils.SysLog != nil {
		utils.SysLog.PutLineAsLog(log)
	} else {
		fmt.Println(log)
	}
}

//接受数据
func (this *WsToTcp) Start() {

	for {

		if this.Conn == nil {
			break
		}

		n, err := this.Conn.Read(this.m_cbDataBuffer[:])

		if err == nil {
			this.RecvServerData(this.m_cbDataBuffer[0:n])
		} else {
			this.PrintLog(this.m_OnlyMark, fmt.Sprintf("RecvServerData -- Failed to read Core server data :error:%s ,length:%d", err.Error(), n))
			this.Close()
			break
		}
		time.Sleep(time.Millisecond * 1)
	}
}

//转发发给前端
func (this *WsToTcp) CallbackToClient(pData []byte) bool {

	if this.m_ws == nil {
		this.PrintLog(this.m_OnlyMark, fmt.Sprintf("this.m_ws"))
		return true
	}

	var err error
	if err = websocket.Message.Send(this.m_ws, pData); err != nil {
		this.PrintLog(this.m_OnlyMark, fmt.Sprintf("Failed to send client data %s", err.Error()))
		//关闭前端
		this.Close()
		return false
	}

	return true
}

//发送给中转 屏蔽验证消息 后面可能要改包
func (this *WsToTcp) CallBackFun(tcpCommand utils.TCP_Command, pData []byte, pSrcData []byte, DataSize uint16, MsgId uint32) bool {

	if tcpCommand.WMainCmdID == utils.MDM_KN_COMMAND && tcpCommand.WSubCmdID == utils.SUB_KN_DETECT_SOCKET {
		this.PrintLog(this.m_OnlyMark, "Received a heartbeat")
		return true
	}

	fmt.Println("ddddd")
	//校验握手
	if tcpCommand.WMainCmdID == utils.MDM_KN_COMMAND && tcpCommand.WSubCmdID == utils.SUB_KN_VALIDATE_SOCKET {

		var CmdCheckReply utils.CMD_S_TCP_CheckReply
		if int(DataSize) != binary.Size(CmdCheckReply) {
			this.PrintLog(this.m_OnlyMark, fmt.Sprintf("CMD_S_TCP_CheckReply Size Error:Current-DataSize:%d Actual-CmdCheckReply:%d", DataSize, binary.Size(CmdCheckReply)))
			return false
		}

		buf := bytes.NewReader(pData[:DataSize])
		if err := binary.Read(buf, binary.LittleEndian, &CmdCheckReply); err != nil {
			this.PrintLog(this.m_OnlyMark, "Packet[CMD_S_TCP_CheckReply] Decryption Failed")
			return false
		}

		//安全验证
		SzOnlyPass := utils.UTF16to8(CmdCheckReply.SzOnlyPass[:])
		//校验MD5
		szCheck := utils.UTF16to8(CmdCheckReply.SzCheckPass[:])

		//创建日志
		this.SysUserLog = utils.MakeNewMyLog("CoreServerlogs", SzOnlyPass+"_sys.log", 50000000, 15)

		//时间变化
		StrTimer := utils.I2s32(this.m_Timestamp)
		//fmt.Println("strtimer:", StrTimer)
		//查找索引
		Strindex := StrTimer[this.m_TransType]
		//fmt.Println("m_TransType:", this.m_TransType)
		//fmt.Println("Strindex:", Strindex)
		//计算乘积
		changestr := utils.I2s((int(Strindex) * int(this.m_TransType)) + 10) //utils.I2s((string((utils.S2i(Strindex))*this.m_TransType) + 10))
		//fmt.Println("changestr:", changestr)
		//字符变换
		NewString := this.insert_flg(StrTimer, changestr, int(this.m_TransType))
		//组合MD5
		NewString += SzOnlyPass
		//fmt.Println("NewString:", NewString)

		//MD5转换
		data := []byte(NewString)
		CheckMd5Byte := md5.Sum(data)
		CheckMd5 := fmt.Sprintf("%x", CheckMd5Byte)
		this.PrintLog(this.m_OnlyMark, fmt.Sprintf("CheckMd5 = %s", CheckMd5))

		//MD5比较
		if CheckMd5 == szCheck {
			this.m_bvalidationSucces = true
			this.PrintLog(this.m_OnlyMark, "md5验证通过")
			fmt.Println("md5验证通过")
		} else {
			this.PrintLog(this.m_OnlyMark, "md5验证失败")
			fmt.Println("md5验证失败")
			return false
		}

		//补填日志
		this.PrintLog(this.m_OnlyMark, fmt.Sprintf("New Clinet Connect Links@%s Verification passed!", this.m_ws.RemoteAddr()))

		//唯一标识
		this.m_OnlyMark = utils.UTF16to8(CmdCheckReply.SzOnlyPass[:])
		this.PrintLog(this.m_OnlyMark, fmt.Sprintf("Decryption Data: DwUserID:%d, SzCheckPass:%v SzOnlyPass:%v ", CmdCheckReply.DwUserID, utils.UTF16to8(CmdCheckReply.SzCheckPass[:]), utils.UTF16to8(CmdCheckReply.SzOnlyPass[:])))

		//开启心跳
		go this.SendDetectSocket()

	}

	//	//拆大厅微信登陆包
	//	if tcpCommand.WMainCmdID == utils.MDM_GP_LOGON && tcpCommand.WSubCmdID == utils.SUB_GP_LOGON_GETWXT0KEN {

	//		var pWeiXinLogon utils.CMD_WX_GetAccessToken
	//		if int(DataSize) != binary.Size(pWeiXinLogon) {
	//			this.PrintLog(this.m_OnlyMark, fmt.Sprintf("CMD_WX_GetAccessToken Size Error:Current-DataSize:%d Actual-CmdCheckReply:%d", DataSize, binary.Size(pWeiXinLogon)))
	//			return false
	//		}

	//		buf := bytes.NewReader(pData[:DataSize])
	//		if err := binary.Read(buf, binary.LittleEndian, &pWeiXinLogon); err != nil {
	//			this.PrintLog(this.m_OnlyMark, "Packet[CMD_WX_GetAccessToken] Decryption Failed")
	//			return false
	//		}

	//		pWeiXinLogon.SzClientIP, _ = utils.ConvertToIntIP(this.m_hc.mIp)
	//		fmt.Println("SUB_GP_LOGON_GETWXT0KEN pWeiXinLogon.SzClientIP", pWeiXinLogon.SzClientIP)
	//		pSrcData = this.m_AssembleBuf.Assemble(tcpCommand.WMainCmdID, tcpCommand.WSubCmdID, pWeiXinLogon, pSrcData)
	//	}

	//	//拆大厅微信登陆包1
	//	if tcpCommand.WMainCmdID == utils.MDM_GP_LOGON && tcpCommand.WSubCmdID == utils.SUB_GP_LOGON_NORMALLOGIN {

	//		var pWeiXinLogon utils.CMD_WX_NormalLogin
	//		if int(DataSize) != binary.Size(pWeiXinLogon) {
	//			this.PrintLog(this.m_OnlyMark, fmt.Sprintf("CMD_WX_NormalLogin Size Error:Current-DataSize:%d Actual-CmdCheckReply:%d", DataSize, binary.Size(pWeiXinLogon)))
	//			return false
	//		}

	//		buf := bytes.NewReader(pData[:DataSize])
	//		if err := binary.Read(buf, binary.LittleEndian, &pWeiXinLogon); err != nil {
	//			this.PrintLog(this.m_OnlyMark, "Packet[CMD_WX_NormalLogin] Decryption Failed")
	//			return false
	//		}

	//		pWeiXinLogon.SzClientIP, _ = utils.ConvertToIntIP(this.m_hc.mIp)
	//		fmt.Println("SUB_GP_LOGON_NORMALLOGIN pWeiXinLogon.SzClientIP", pWeiXinLogon.SzClientIP)
	//		pSrcData = this.m_AssembleBuf.Assemble(tcpCommand.WMainCmdID, tcpCommand.WSubCmdID, pWeiXinLogon, pSrcData)
	//	}

	//	//拆房间登陆包
	//	if tcpCommand.WMainCmdID == utils.MDM_GR_LOGON && tcpCommand.WSubCmdID == utils.SUB_GR_LOGON_USERID {

	//		var pWeiXinLogon utils.CMD_GR_LogonUserID
	//		if int(DataSize) != binary.Size(pWeiXinLogon) {
	//			this.PrintLog(this.m_OnlyMark, fmt.Sprintf("CMD_GR_LogonUserID Size Error:Current-DataSize:%d Actual-CmdCheckReply:%d", DataSize, binary.Size(pWeiXinLogon)))
	//			return false
	//		}

	//		buf := bytes.NewReader(pData[:DataSize])
	//		if err := binary.Read(buf, binary.LittleEndian, &pWeiXinLogon); err != nil {
	//			this.PrintLog(this.m_OnlyMark, "Packet[CMD_GR_LogonUserID] Decryption Failed")
	//			return false
	//		}

	//		pWeiXinLogon.DwClientIP, _ = utils.ConvertToIntIP(this.m_hc.mIp)
	//		fmt.Println("SUB_GR_LOGON_USERID pWeiXinLogon.SzClientIP", pWeiXinLogon.DwClientIP)
	//		pSrcData = this.m_AssembleBuf.Assemble(tcpCommand.WMainCmdID, tcpCommand.WSubCmdID, pWeiXinLogon, pSrcData)

	//	}

	//安全验证不通过
	if this.m_bvalidationSucces == false {
		this.PrintLog(this.m_OnlyMark, "验证不通过发送消息")
		return false
	}

	if this.Conn != nil {
		//TCP 发送
		n, err := this.Conn.Write(pSrcData)
		if err == nil {
			this.PrintLog(this.m_OnlyMark, fmt.Sprintf("Send Data To CoreServer Success Bytes Size:%d", n))
			return true

		} else {
			this.PrintLog(this.m_OnlyMark, fmt.Sprintf("Send Data To CoreServer Failed Bytes Size:%d", n))
			this.Close()
			return false
		}
	} else {
		this.PrintLog(this.m_OnlyMark, fmt.Sprintf("Send unusual !! the this.Conn = nil"))
	}

	return true
}

//发送心跳
func (this *WsToTcp) SendDetectSocket() {

	this.PrintLog(this.m_OnlyMark, " Start  heartbeat Server Is Runing Timer:5s")

	t1 := time.NewTimer(time.Second * 5)
ForEnd:
	for {
		select {
		case <-this.Closechan:
			this.PrintLog(this.m_OnlyMark, "接受到断开信号")
			break ForEnd
		case <-t1.C:
			this.PrintLog(this.m_OnlyMark, "5s timer")
			t1.Reset(time.Second * 5)
			if this.Conn == nil {
				break ForEnd
			}
			if this.m_NetBuf.SendData(utils.MDM_KN_COMMAND, utils.SUB_KN_DETECT_SOCKET, nil, 0, this.m_ws, 0, this.m_OnlyMark) == false {
				this.PrintLog(this.m_OnlyMark, "心跳发送失败 断开网络")
				this.Close()
				break ForEnd
			}
		}
	}

	this.PrintLog(this.m_OnlyMark, "heartbeat Server End")
}

//转发给前端 通过回调
func (this *WsToTcp) RecvServerData(pData []byte) {
	this.m_RecvNetBuf.DecryptData(pData, this.CallbackToClient, nil, this.m_OnlyMark)
}

//网络发送
func (this *WsToTcp) SendData(pData []byte) bool {

	if this.m_NetBuf.DecryptData(pData, nil, this.CallBackFun, this.m_OnlyMark) {
		return true
	} else {
		this.Close()
	}

	return true
}

//网络关闭
func (this *WsToTcp) Close() {

	this.PrintLog(this.m_OnlyMark, "网络关闭")

	this.lock.Lock()
	defer this.lock.Unlock()

	if this.Conn != nil {
		this.Conn.Close()
		this.Conn = nil
		this.PrintLog(this.m_OnlyMark, "Close Core Server link")
		this.Closechan <- true
	}

	if this.m_ws != nil {
		this.m_ws.Close()
		this.m_ws = nil
		this.PrintLog(this.m_OnlyMark, "Close Client Link")
	}
}

func (this *WsToTcp) insert_flg(str, flg string, sn int) string {
	var Str1 = str[0:sn]
	var str2 = str[sn:len(str)]
	var newstr = Str1 + flg + str2
	return newstr
}
